/**
 * @file MyIIC.c
 * @author leijiapeng (email:leijiapeng123@163.com)
 * @brief
 * @version 0.1
 * @date 2025-09-18
 *
 * @copyright Copyright (c) 2025
 *
 */
#include "iic.h"

/**
 * @brief 主机控制SCL
 *
 * @param val [in] SCL的状态,0或1
 */
static void MyIIC_WriteSCL(uint8_t val)
{
    HAL_GPIO_WritePin(MyIIC_SCL_GPIO_PORT, MyIIC_SCL_GPIO_PIN, (GPIO_PinState)val);
#error if mcu clock speed is too high, you should add a delay here, other ignore this error
}

/**
 * @brief 主机控制SDA
 *
 * @param val [in] SDA的状态,0或1
 */
static void MyIIC_WriteSDA(uint8_t val) { HAL_GPIO_WritePin(MyIIC_SDA_GPIO_PORT, MyIIC_SDA_GPIO_PIN, (GPIO_PinState)val); }

/**
 * @brief 读取SDA的状态
 *
 * @return SDA线的状态,0或1
 */
static GPIO_PinState MyIIC_ReadSDA(void)
{
    uint8_t ret;
    ret = HAL_GPIO_ReadPin(MyIIC_SDA_GPIO_PORT, MyIIC_SDA_GPIO_PIN);
    return ret;
}

/**
 * @brief MyIIC开始时序,SCL高电平期间拉低SDA
 *
 */
void MyIIC_Start(void)
{
    MyIIC_WriteSDA(1);
    MyIIC_WriteSCL(1);
    MyIIC_WriteSDA(0);
    MyIIC_WriteSCL(0); // 拉低SCL,方便拼接下一个时序
}

/**
 * @brief MyIIC结束时序,SCL高电平期间释放SDA
 *
 */
void MyIIC_Stop(void)
{
    MyIIC_WriteSDA(0);
    MyIIC_WriteSCL(1);
    MyIIC_WriteSDA(1);
}

/**
 * @brief 将字节发送到MyIIC总线上
 *
 * @param byte [in] 待发送的字节
 */
void MyIIC_SendByte(uint8_t byte)
{
    int i;
    for (i = 0; i < 8; i++)
    {
        MyIIC_WriteSDA(!!(byte & (0x80 >> i))); // 高位先行，两次逻辑取反!!会让任何不为0的数变成1
        MyIIC_WriteSCL(1);                      // 释放SCL,从机会在SCL高电平期间读取SDA的数据
        MyIIC_WriteSCL(0);                      // 拉低SCL,主机开始发送下一位数据
    }
}

/**
 * @brief 接收MyIIC总线上的字节数据
 *
 * @return 接收到的字节数据
 */
uint8_t MyIIC_ReceiveByte(void)
{
    uint8_t ret = 0x00;
    MyIIC_WriteSDA(1); // 主机先释放SDA,避免干扰从机的数据
    for (int i = 0; i < 8; ++i)
    {
        MyIIC_WriteSCL(1);        // 主机释放SCL,此时从机不允许操纵SDA
        if (MyIIC_ReadSDA() != 0) // 主机读取SDA的数据
        {
            ret |= (0x80 >> i);
        }
        MyIIC_WriteSCL(0); // 主机拉低SCL,从机将下一位数据放到SDA
    }
    return ret;
}

/**
 * @brief 发送应答位
 *
 */
void MyIIC_SendACK(void)
{
    MyIIC_WriteSDA(0); // 主机发送应答位
    MyIIC_WriteSCL(1);   // 主机释放SCL,从机将在此时读取SDA的数据
    MyIIC_WriteSCL(0);   // 拉低SCL,方便拼接下一个时序
}

/**
 * @brief 发送非应答位
 *
 */
void MyIIC_SendNACK(void)
{
    MyIIC_WriteSDA(1); // 主机发送非应答位
    MyIIC_WriteSCL(1);   // 主机释放SCL,从机将在此时读取SDA的数据
    MyIIC_WriteSCL(0);   // 拉低SCL,方便拼接下一个时序
}

/**
 * @brief 接收总线上的应答位
 *
 * @return 应答位,0应答,1非应答
 */
uint8_t MyIIC_ReceiveACK(void)
{
    uint8_t ack = 1;     // 默认无应答
    MyIIC_WriteSDA(1);     // 主机释放SDA,避免干扰到从机的SDA数据
    MyIIC_WriteSCL(1);     // 释放SCL,此时从机不允许发送SDA
    ack = MyIIC_ReadSDA(); // 读取从机发送的应答位
    MyIIC_WriteSCL(0);     // 拉低SCL,方便拼接下一个时序
    return ack;
}